package com.ccys.netty.handler;

import com.alibaba.fastjson.JSONObject;
import com.ccys.common.enums.CodeEnum;
import com.ccys.common.util.JedisUtil;
import com.ccys.common.util.Kit;
import com.ccys.common.util.StringUtil;
import com.ccys.netty.config.NettyConfig;

import com.ccys.netty.content.BaseConstant;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;

import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.util.AttributeKey;

import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author cloud fly
 * @description 描述
 * @date 2024/3/1
 * 参考https://blog.csdn.net/baidu_19473529/article/details/89442402
 */
@Slf4j
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
    public static Map<String,ChannelHandlerContext> CHANNEL_MAP = new ConcurrentHashMap();

    public static AtomicInteger nConnection = new AtomicInteger();

    @Override
    public void channelRegistered(ChannelHandlerContext ctx)  {
        log.info("========客户端注册=======");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx)  {
        ctx.channel().close();
        String channelBookingId = WebSocketFrameHandler.getChannelBookingId(ctx);
        if(StringUtil.isNotEmpty(channelBookingId)) {
            //删除缓存的通道关系
            NettyConfig.getUserChannelMap().remove(channelBookingId);
            //删除缓存的通道状态
            JedisUtil.del("bookingId:" + channelBookingId,CodeEnum.REDIS_HEARTBEAT.codeOf());
        }
        log.info("========客户端注销=======");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx)  {
        log.info("========客户端连接=======");
        nConnection.incrementAndGet();
        log.info("========当前连接数:{}",nConnection.get());

    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {

        log.info("=========读取消息==========");
        if (frame instanceof TextWebSocketFrame) {
            String text = ((TextWebSocketFrame) frame).text();
            // 在这里处理接收到的文本消息
            System.out.println("Received message: " + text);
            if("ping".equals(text)) {
                ctx.writeAndFlush( new TextWebSocketFrame("pong"));
            }else {
                String response = "Hello, client  receive  TextWebSocketFrame message" + text;
                TextWebSocketFrame textFrame = new TextWebSocketFrame(response);
                ctx.writeAndFlush(textFrame);
            }
            // 可以在这里回复客户端消息
        } else {
            log.error("Unsupported frame type: " + frame.getClass().getName());
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.info("读取消息为:{}",msg);
        if(msg instanceof FullHttpRequest){
            //Android  app端 测试使用的是这种方式
            FullHttpRequest data = (FullHttpRequest) msg;
            String uri = data.uri();
            log.info("客户端连接Url= " + data.uri());
            if(StringUtil.isNotEmpty(uri)) {
                JSONObject jsonObject = WebSocketFrameHandler.splitString(uri);
                if(jsonObject != null) {
                    // 获取用户ID
                    String bookingId = jsonObject.getString("booking_id");
                    // 将用户ID作为自定义属性加入到channel中，方便随时channel中获取用户ID
                    AttributeKey<String> key = AttributeKey.valueOf("bookingId");
                    ctx.channel().attr(key).setIfAbsent(bookingId);
                    // 关联channel
                    NettyConfig.getUserChannelMap().put(bookingId,ctx);
                    //通道保存到redis
                    String setex = JedisUtil.setex("bookingId:" + bookingId, BaseConstant.HEARTBEAT + 10, ctx.channel().id().asLongText(), CodeEnum.REDIS_HEARTBEAT.codeOf());
                    log.info("bookingId通道缓存结果--->" + setex);
                    log.info("在线bookingId:" + Kit.getOnLineBookingIds());
                }

            }
            String response = "Hello, client!";
            TextWebSocketFrame textFrame = new TextWebSocketFrame(response);
            ctx.writeAndFlush(textFrame);
            data.setUri("/websocket");
            super.channelRead(ctx, data);

        }else {
            super.channelRead(ctx, msg);

        }

    }

       /**
        * @description 解析url后面的参数 转json对象
        * @date     2024/3/4
        * @author   cloud fly
        */
    public static JSONObject splitString(String uri) {
        if(StringUtil.isEmpty(uri)) {
            return new JSONObject();
        }
        String param = uri.substring(uri.indexOf("?") + 1);
        //String param = "http://www.aa.bb/ws?booking_id=777&member_id=777&userId=777";

        // 创建一个 JSONObject 对象
        JSONObject jsonObject = new JSONObject();

        // 将字符串按照 "&" 分割成键值对数组
        String[] pairs = param.split("&");

        // 遍历键值对数组，将键值对分别添加到 JSONObject 中
        for (String pair : pairs) {
            String[] keyValue = pair.split("=");
            if (keyValue.length == 2) {
                String key = keyValue[0];
                String value = keyValue[1];
                jsonObject.put(key, value);
            }
        }
        // 打印生成的 JSON 对象
        System.out.println(jsonObject.toJSONString());
        return jsonObject;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        if (cause instanceof IllegalArgumentException) {
            System.err.println("Invalid message format: " + cause.getMessage());
        } else {
            cause.printStackTrace();
        }
    }

       /**
        * @description 获取ChannelBookingId
        * @date     2024/3/4
        * @author   cloud fly
        */
    public static String getChannelBookingId(ChannelHandlerContext ctx){
        AttributeKey<String> key = AttributeKey.valueOf("bookingId");
        return ctx.channel().attr(key).get();
    }

    /*JSONObject jsonObject = new JSONObject();
        jsonObject.put("channelId",ctx.channel().id().asLongText());
        jsonObject.put("state","success");
        jsonObject.put("userId", "666666");
        ctx.channel().writeAndFlush(new TextWebSocketFrame("收到客户端连接时回复消息：" + jsonObject.toJSONString()));*/
}
